/*******************************************************************************
 ** Qt Advanced Docking System
 ** Copyright (C) 2017 Uwe Kindler
 **
 ** This library is free software; you can redistribute it and/or
 ** modify it under the terms of the GNU Lesser General Public
 ** License as published by the Free Software Foundation; either
 ** version 2.1 of the License, or (at your option) any later version.
 **
 ** This library is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ** Lesser General Public License for more details.
 **
 ** You should have received a copy of the GNU Lesser General Public
 ** License along with this library; If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

//============================================================================
/// \file   FloatingDockContainer.cpp
/// \author Uwe Kindler
/// \date   01.03.2017
/// \brief  Implementation of CFloatingDockContainer class
//============================================================================

//============================================================================
//                                   INCLUDES
//============================================================================
#include "FloatingDockContainer.h"

#include <iostream>

#include <QBoxLayout>
#include <QApplication>
#include <QMouseEvent>
#include <QPointer>
#include <QAction>
#include <QDebug>
#include <QAbstractButton>
#include <QElapsedTimer>
#include <QTime>

#include "DockContainerWidget.h"
#include "DockAreaWidget.h"
#include "DockManager.h"
#include "DockWidget.h"
#include "DockOverlay.h"

#ifdef Q_OS_WIN
#include <windows.h>
#ifdef _MSC_VER
#pragma comment(lib, "User32.lib")
#endif
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include "linux/FloatingWidgetTitleBar.h"
#include <xcb/xcb.h>
#endif

namespace ads
{
#ifdef Q_OS_WIN
#if 0 // set to 1 if you need this function for debugging
/**
 * 用于调试，将Windows消息标识符转换为字符串
 */
static const char* windowsMessageString(int MessageId)
{
    switch (MessageId)
    {
    case 0: return "WM_NULL";
    case 1: return "WM_CREATE";
    case 2: return "WM_DESTROY";
    case 3: return "WM_MOVE";
    case 5: return "WM_SIZE";
    case 6: return "WM_ACTIVATE";
    case 7: return "WM_SETFOCUS";
    case 8: return "WM_KILLFOCUS";
    case 10: return "WM_ENABLE";
    case 11: return "WM_SETREDRAW";
    case 12: return "WM_SETTEXT";
    case 13: return "WM_GETTEXT";
    case 14: return "WM_GETTEXTLENGTH";
    case 15: return "WM_PAINT";
    case 16: return "WM_CLOSE";
    case 17: return "WM_QUERYENDSESSION";
    case 18: return "WM_QUIT";
    case 19: return "WM_QUERYOPEN";
    case 20: return "WM_ERASEBKGND";
    case 21: return "WM_SYSCOLORCHANGE";
    case 22: return "WM_ENDSESSION";
    case 24: return "WM_SHOWWINDOW";
    case 25: return "WM_CTLCOLOR";
    case 26: return "WM_WININICHANGE";
    case 27: return "WM_DEVMODECHANGE";
    case 28: return "WM_ACTIVATEAPP";
    case 29: return "WM_FONTCHANGE";
    case 30: return "WM_TIMECHANGE";
    case 31: return "WM_CANCELMODE";
    case 32: return "WM_SETCURSOR";
    case 33: return "WM_MOUSEACTIVATE";
    case 34: return "WM_CHILDACTIVATE";
    case 35: return "WM_QUEUESYNC";
    case 36: return "WM_GETMINMAXINFO";
    case 38: return "WM_PAINTICON";
    case 39: return "WM_ICONERASEBKGND";
    case 40: return "WM_NEXTDLGCTL";
    case 42: return "WM_SPOOLERSTATUS";
    case 43: return "WM_DRAWITEM";
    case 44: return "WM_MEASUREITEM";
    case 45: return "WM_DELETEITEM";
    case 46: return "WM_VKEYTOITEM";
    case 47: return "WM_CHARTOITEM";
    case 48: return "WM_SETFONT";
    case 49: return "WM_GETFONT";
    case 50: return "WM_SETHOTKEY";
    case 51: return "WM_GETHOTKEY";
    case 55: return "WM_QUERYDRAGICON";
    case 57: return "WM_COMPAREITEM";
    case 61: return "WM_GETOBJECT";
    case 65: return "WM_COMPACTING";
    case 68: return "WM_COMMNOTIFY";
    case 70: return "WM_WINDOWPOSCHANGING";
    case 71: return "WM_WINDOWPOSCHANGED";
    case 72: return "WM_POWER";
    case 73: return "WM_COPYGLOBALDATA";
    case 74: return "WM_COPYDATA";
    case 75: return "WM_CANCELJOURNAL";
    case 78: return "WM_NOTIFY";
    case 80: return "WM_INPUTLANGCHANGEREQUEST";
    case 81: return "WM_INPUTLANGCHANGE";
    case 82: return "WM_TCARD";
    case 83: return "WM_HELP";
    case 84: return "WM_USERCHANGED";
    case 85: return "WM_NOTIFYFORMAT";
    case 123: return "WM_CONTEXTMENU";
    case 124: return "WM_STYLECHANGING";
    case 125: return "WM_STYLECHANGED";
    case 126: return "WM_DISPLAYCHANGE";
    case 127: return "WM_GETICON";
    case 128: return "WM_SETICON";
    case 129: return "WM_NCCREATE";
    case 130: return "WM_NCDESTROY";
    case 131: return "WM_NCCALCSIZE";
    case 132: return "WM_NCHITTEST";
    case 133: return "WM_NCPAINT";
    case 134: return "WM_NCACTIVATE";
    case 135: return "WM_GETDLGCODE";
    case 136: return "WM_SYNCPAINT";
    case 160: return "WM_NCMOUSEMOVE";
    case 161: return "WM_NCLBUTTONDOWN";
    case 162: return "WM_NCLBUTTONUP";
    case 163: return "WM_NCLBUTTONDBLCLK";
    case 164: return "WM_NCRBUTTONDOWN";
    case 165: return "WM_NCRBUTTONUP";
    case 166: return "WM_NCRBUTTONDBLCLK";
    case 167: return "WM_NCMBUTTONDOWN";
    case 168: return "WM_NCMBUTTONUP";
    case 169: return "WM_NCMBUTTONDBLCLK";
    case 171: return "WM_NCXBUTTONDOWN";
    case 172: return "WM_NCXBUTTONUP";
    case 173: return "WM_NCXBUTTONDBLCLK";
    case 176: return "EM_GETSEL";
    case 177: return "EM_SETSEL";
    case 178: return "EM_GETRECT";
    case 179: return "EM_SETRECT";
    case 180: return "EM_SETRECTNP";
    case 181: return "EM_SCROLL";
    case 182: return "EM_LINESCROLL";
    case 183: return "EM_SCROLLCARET";
    case 185: return "EM_GETMODIFY";
    case 187: return "EM_SETMODIFY";
    case 188: return "EM_GETLINECOUNT";
    case 189: return "EM_LINEINDEX";
    case 190: return "EM_SETHANDLE";
    case 191: return "EM_GETHANDLE";
    case 192: return "EM_GETTHUMB";
    case 193: return "EM_LINELENGTH";
    case 194: return "EM_REPLACESEL";
    case 195: return "EM_SETFONT";
    case 196: return "EM_GETLINE";
    case 197: return "EM_LIMITTEXT / EM_SETLIMITTEXT";
    case 198: return "EM_CANUNDO";
    case 199: return "EM_UNDO";
    case 200: return "EM_FMTLINES";
    case 201: return "EM_LINEFROMCHAR";
    case 202: return "EM_SETWORDBREAK";
    case 203: return "EM_SETTABSTOPS";
    case 204: return "EM_SETPASSWORDCHAR";
    case 205: return "EM_EMPTYUNDOBUFFER";
    case 206: return "EM_GETFIRSTVISIBLELINE";
    case 207: return "EM_SETREADONLY";
    case 209: return "EM_SETWORDBREAKPROC / EM_GETWORDBREAKPROC";
    case 210: return "EM_GETPASSWORDCHAR";
    case 211: return "EM_SETMARGINS";
    case 212: return "EM_GETMARGINS";
    case 213: return "EM_GETLIMITTEXT";
    case 214: return "EM_POSFROMCHAR";
    case 215: return "EM_CHARFROMPOS";
    case 216: return "EM_SETIMESTATUS";
    case 217: return "EM_GETIMESTATUS";
    case 224: return "SBM_SETPOS";
    case 225: return "SBM_GETPOS";
    case 226: return "SBM_SETRANGE";
    case 227: return "SBM_GETRANGE";
    case 228: return "SBM_ENABLE_ARROWS";
    case 230: return "SBM_SETRANGEREDRAW";
    case 233: return "SBM_SETSCROLLINFO";
    case 234: return "SBM_GETSCROLLINFO";
    case 235: return "SBM_GETSCROLLBARINFO";
    case 240: return "BM_GETCHECK";
    case 241: return "BM_SETCHECK";
    case 242: return "BM_GETSTATE";
    case 243: return "BM_SETSTATE";
    case 244: return "BM_SETSTYLE";
    case 245: return "BM_CLICK";
    case 246: return "BM_GETIMAGE";
    case 247: return "BM_SETIMAGE";
    case 248: return "BM_SETDONTCLICK";
    case 255: return "WM_INPUT";
    case 256: return "WM_KEYDOWN";
    case 257: return "WM_KEYUP";
    case 258: return "WM_CHAR";
    case 259: return "WM_DEADCHAR";
    case 260: return "WM_SYSKEYDOWN";
    case 261: return "WM_SYSKEYUP";
    case 262: return "WM_SYSCHAR";
    case 263: return "WM_SYSDEADCHAR";
    case 265: return "WM_UNICHAR / WM_WNT_CONVERTREQUESTEX";
    case 266: return "WM_CONVERTREQUEST";
    case 267: return "WM_CONVERTRESULT";
    case 268: return "WM_INTERIM";
    case 269: return "WM_IME_STARTCOMPOSITION";
    case 270: return "WM_IME_ENDCOMPOSITION";
    case 272: return "WM_INITDIALOG";
    case 273: return "WM_COMMAND";
    case 274: return "WM_SYSCOMMAND";
    case 275: return "WM_TIMER";
    case 276: return "WM_HSCROLL";
    case 277: return "WM_VSCROLL";
    case 278: return "WM_INITMENU";
    case 279: return "WM_INITMENUPOPUP";
    case 280: return "WM_SYSTIMER";
    case 287: return "WM_MENUSELECT";
    case 288: return "WM_MENUCHAR";
    case 289: return "WM_ENTERIDLE";
    case 290: return "WM_MENURBUTTONUP";
    case 291: return "WM_MENUDRAG";
    case 292: return "WM_MENUGETOBJECT";
    case 293: return "WM_UNINITMENUPOPUP";
    case 294: return "WM_MENUCOMMAND";
    case 295: return "WM_CHANGEUISTATE";
    case 296: return "WM_UPDATEUISTATE";
    case 297: return "WM_QUERYUISTATE";
    case 306: return "WM_CTLCOLORMSGBOX";
    case 307: return "WM_CTLCOLOREDIT";
    case 308: return "WM_CTLCOLORLISTBOX";
    case 309: return "WM_CTLCOLORBTN";
    case 310: return "WM_CTLCOLORDLG";
    case 311: return "WM_CTLCOLORSCROLLBAR";
    case 312: return "WM_CTLCOLORSTATIC";
    case 512: return "WM_MOUSEMOVE";
    case 513: return "WM_LBUTTONDOWN";
    case 514: return "WM_LBUTTONUP";
    case 515: return "WM_LBUTTONDBLCLK";
    case 516: return "WM_RBUTTONDOWN";
    case 517: return "WM_RBUTTONUP";
    case 518: return "WM_RBUTTONDBLCLK";
    case 519: return "WM_MBUTTONDOWN";
    case 520: return "WM_MBUTTONUP";
    case 521: return "WM_MBUTTONDBLCLK";
    case 522: return "WM_MOUSEWHEEL";
    case 523: return "WM_XBUTTONDOWN";
    case 524: return "WM_XBUTTONUP";
    case 525: return "WM_XBUTTONDBLCLK";
    case 528: return "WM_PARENTNOTIFY";
    case 529: return "WM_ENTERMENULOOP";
    case 530: return "WM_EXITMENULOOP";
    case 531: return "WM_NEXTMENU";
    case 532: return "WM_SIZING";
    case 533: return "WM_CAPTURECHANGED";
    case 534: return "WM_MOVING";
    case 536: return "WM_POWERBROADCAST";
    case 537: return "WM_DEVICECHANGE";
    case 544: return "WM_MDICREATE";
    case 545: return "WM_MDIDESTROY";
    case 546: return "WM_MDIACTIVATE";
    case 547: return "WM_MDIRESTORE";
    case 548: return "WM_MDINEXT";
    case 549: return "WM_MDIMAXIMIZE";
    case 550: return "WM_MDITILE";
    case 551: return "WM_MDICASCADE";
    case 552: return "WM_MDIICONARRANGE";
    case 553: return "WM_MDIGETACTIVE";
    case 560: return "WM_MDISETMENU";
    case 561: return "WM_ENTERSIZEMOVE";
    case 562: return "WM_EXITSIZEMOVE";
    case 563: return "WM_DROPFILES";
    case 564: return "WM_MDIREFRESHMENU";
    case 640: return "WM_IME_REPORT";
    case 641: return "WM_IME_SETCONTEXT";
    case 642: return "WM_IME_NOTIFY";
    case 643: return "WM_IME_CONTROL";
    case 644: return "WM_IME_COMPOSITIONFULL";
    case 645: return "WM_IME_SELECT";
    case 646: return "WM_IME_CHAR";
    case 648: return "WM_IME_REQUEST";
    case 656: return "WM_IME_KEYDOWN";
    case 657: return "WM_IME_KEYUP";
    case 672: return "WM_NCMOUSEHOVER";
    case 673: return "WM_MOUSEHOVER";
    case 674: return "WM_NCMOUSELEAVE";
    case 675: return "WM_MOUSELEAVE";
    case 768: return "WM_CUT";
    case 769: return "WM_COPY";
    case 770: return "WM_PASTE";
    case 771: return "WM_CLEAR";
    case 772: return "WM_UNDO";
    case 773: return "WM_RENDERFORMAT";
    case 774: return "WM_RENDERALLFORMATS";
    case 775: return "WM_DESTROYCLIPBOARD";
    case 776: return "WM_DRAWCLIPBOARD";
    case 777: return "WM_PAINTCLIPBOARD";
    case 778: return "WM_VSCROLLCLIPBOARD";
    case 779: return "WM_SIZECLIPBOARD";
    case 780: return "WM_ASKCBFORMATNAME";
    case 781: return "WM_CHANGECBCHAIN";
    case 782: return "WM_HSCROLLCLIPBOARD";
    case 783: return "WM_QUERYNEWPALETTE";
    case 784: return "WM_PALETTEISCHANGING";
    case 785: return "WM_PALETTECHANGED";
    case 786: return "WM_HOTKEY";
    case 791: return "WM_PRINT";
    case 792: return "WM_PRINTCLIENT";
    case 793: return "WM_APPCOMMAND";
    case 856: return "WM_HANDHELDFIRST";
    case 863: return "WM_HANDHELDLAST";
    case 864: return "WM_AFXFIRST";
    case 895: return "WM_AFXLAST";
    case 896: return "WM_PENWINFIRST";
    case 897: return "WM_RCRESULT";
    case 898: return "WM_HOOKRCRESULT";
    case 899: return "WM_GLOBALRCCHANGE / WM_PENMISCINFO";
    case 900: return "WM_SKB";
    case 901: return "WM_HEDITCTL / WM_PENCTL";
    case 902: return "WM_PENMISC";
    case 903: return "WM_CTLINIT";
    case 904: return "WM_PENEVENT";
    case 911: return "WM_PENWINLAST";
    default:
    	return "unknown WM_ message";
	}

	return "unknown WM_ message";
}
#endif
#endif


static unsigned int zOrderCounter = 0;
/**
 * 私有数据类的CFloatingDockContainer类（pimpl）
 */
struct FloatingDockContainerPrivate
{
    CFloatingDockContainer *_this;  // 指向CFloatingDockContainer的指针
    CDockContainerWidget *DockContainer;  // Dock容器指针
    unsigned int zOrderIndex = ++zOrderCounter;  // zOrder索引
    QPointer<CDockManager> DockManager;  // CDockManager指针
    eDragState DraggingState = DraggingInactive;  // 拖动状态
    QPoint DragStartMousePosition;  // 拖动开始时的鼠标位置
    CDockContainerWidget *DropContainer = nullptr;  // 拖放容器指针
    CDockAreaWidget *SingleDockArea = nullptr;  // 单个Dock区域指针
    QPoint DragStartPos;  // 拖动开始时的位置
    bool Hiding = false;  // 是否隐藏
    bool AutoHideChildren = true;  // 是否自动隐藏子项
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    QWidget* MouseEventHandler = nullptr;  // 鼠标事件处理器指针
    CFloatingWidgetTitleBar* TitleBar = nullptr;  // 浮动窗口标题栏指针
    bool IsResizing = false;  // 是否正在调整大小
    bool MousePressed = false;  // 鼠标是否按下
#endif
    /**
     * 私有数据构造函数
     */
    FloatingDockContainerPrivate(CFloatingDockContainer *_public);
    void titleMouseReleaseEvent();  // 标题鼠标释放事件
    void updateDropOverlays(const QPoint &GlobalPos);  // 更新拖放覆盖层
    /**
     * 如果给定的配置标志被设置，则返回true
     */
    static bool testConfigFlag(CDockManager::eConfigFlag Flag)
    {
        return CDockManager::testConfigFlag(Flag);
    }
    /**
     * 检测某个状态是否处于活动状态
     */
    bool isState(eDragState StateId) const
    {
        return StateId == DraggingState;
    }
    /**
     * 设置拖动状态并发布FloatingWidgetDragStartEvent事件，如果拖动开始
     */
    void setState(eDragState StateId)
    {
        if (DraggingState == StateId)
        {
            return;
        }
        DraggingState = StateId;
        if (DraggingFloatingWidget == DraggingState)
        {
            qApp->postEvent(_this, new QEvent((QEvent::Type)internal::FloatingWidgetDragStartEvent));
        }
    }
    void setWindowTitle(const QString &Text)
    {
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
        if (TitleBar)
        {
            TitleBar->setTitle(Text);
        }
#endif
        _this->setWindowTitle(Text);
    }

	// 根据 CDockManager::FloatingContainerHasWidgetTitle 标志，在浮动窗口的 windowTitle() 中反映当前停靠窗口的标题
void reflectCurrentWidget(CDockWidget* CurrentWidget)
{
    // 如果配置为这样做，则反映 CurrentWidget 的标题，否则将应用程序名称显示为窗口标题
    if (testConfigFlag(CDockManager::FloatingContainerHasWidgetTitle)) {
        setWindowTitle(CurrentWidget->windowTitle());
    } else {
        setWindowTitle(floatingContainersTitle());
    }

    // 如果配置为这样做，则反映 CurrentWidget 的图标，否则将应用程序图标显示为窗口图标
    QIcon CurrentWidgetIcon = CurrentWidget->icon();
    if (testConfigFlag(CDockManager::FloatingContainerHasWidgetIcon) && !CurrentWidgetIcon.isNull()) {
        _this->setWindowIcon(CurrentWidget->icon());
    } else {
        _this->setWindowIcon(QApplication::windowIcon());
    }
}

// 处理拖动浮动窗口时按下的 Esc 键
void handleEscapeKey();

// 返回所有 FloatingContainer 使用的标题，该标题不反映当前停靠窗口的标题
// 如果没有使用 CDockManager::setFloatingContainersTitle() 设置标题，则返回 QGuiApplication::applicationDisplayName()
static QString floatingContainersTitle()
{
    return CDockManager::floatingContainersTitle();
}
};
// struct FloatingDockContainerPrivate

//============================================================================
// FloatingDockContainerPrivate 构造函数
FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContainer *_public) :
    _this(_public)
{
}

//============================================================================
// 处理标题栏的鼠标释放事件
void FloatingDockContainerPrivate::titleMouseReleaseEvent()
{
    // 设置状态为 DraggingInactive
    setState(DraggingInactive);
    
    // 如果没有 DropContainer，返回
    if (!DropContainer)
    {
        return;
    }
    
    // 检查鼠标释放位置下的 drop 区域是否有效
    if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
        || DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
    {
        CDockOverlay *Overlay = DockManager->containerOverlay();
        
        // 如果 drop overlay 的矩形无效，则使用 dock area overlay
        if (!Overlay->dropOverlayRect().isValid())
        {
            Overlay = DockManager->dockAreaOverlay();
        }
        
        // 如果将要放置的区域是 autohide sidebar 区域，则不进行调整大小，以保持 dock area 的初始大小
        if (!ads::internal::isSideBarArea(Overlay->dropAreaUnderCursor()))
        {
            // 将浮动窗口调整为高亮显示的 drop 区域矩形的大小
            QRect Rect = Overlay->dropOverlayRect();
            int FrameWidth = (_this->frameSize().width() - _this->rect().width()) / 2;
            int TitleBarHeight = _this->frameSize().height() - _this->rect().height() - FrameWidth;
            
            if (Rect.isValid())
            {
                QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
                TopLeft.ry() += TitleBarHeight;
                _this->setGeometry(QRect(TopLeft, QSize(Rect.width(), Rect.height() - TitleBarHeight)));
                QApplication::processEvents();
            }
        }
        
        // 在鼠标位置将浮动窗口放置到 drop container 中
        DropContainer->dropFloatingWidget(_this, QCursor::pos());
    }
    
    // 隐藏 container 和 dock area 的 overlay
    DockManager->containerOverlay()->hideOverlay();
    DockManager->dockAreaOverlay()->hideOverlay();
}

//============================================================================
// 更新 drop overlays 的显示位置
void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
{
    // 如果浮动的 dock container 不可见或者没有 dock manager，则返回
    if (!_this->isVisible() || !DockManager)
    {
        return;
    }
    
    // 防止在模态对话框激活时显示 drop overlays 和进行 docking
    #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    if (qApp->activeModalWidget())
    {
        return;
    }
    #endif
    
    // 获取 dock containers
    auto Containers = DockManager->dockContainers();
    CDockContainerWidget *TopContainer = nullptr;
    
    // 根据鼠标位置找到顶部的 container
    for (auto ContainerWidget : Containers)
    {
        if (!ContainerWidget->isVisible())
        {
            continue;
        }
        
        if (DockContainer == ContainerWidget)
        {
            continue;
        }
        
        QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
        
        if (ContainerWidget->rect().contains(MappedPos))
        {
            if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
            {
                TopContainer = ContainerWidget;
            }
        }
    }
    
    // 将顶部的 container 设置为 drop container
    DropContainer = TopContainer;
    
    auto ContainerOverlay = DockManager->containerOverlay();
    auto DockAreaOverlay = DockManager->dockAreaOverlay();
    
    // 如果没有 top container，则隐藏 overlay 并返回
    if (!TopContainer)
    {
        ContainerOverlay->hideOverlay();
        DockAreaOverlay->hideOverlay();
        return;
    }
    
    int VisibleDockAreas = TopContainer->visibleDockAreaCount();
    DockWidgetAreas AllowedContainerAreas = (VisibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
    auto DockArea = TopContainer->dockAreaAt(GlobalPos);
    
    // 如果 dock container 只包含一个 DockArea，则需要考虑 allowed areas - 只有 center area 是相关的，因为其他 allowed areas 都是从 container 中来的
    if (VisibleDockAreas == 1 && DockArea)
    {
        AllowedContainerAreas.setFlag(CenterDockWidgetArea, DockArea->allowedAreas().testFlag(CenterDockWidgetArea));
    }
    
    // 如果 dock widget 是可固定的，则添加 AutoHideDockAreas 到 AllowedContainerAreas
    if (DockContainer->features().testFlag(CDockWidget::DockWidgetPinnable))
    {
        AllowedContainerAreas |= AutoHideDockAreas;
    }
    
    // 设置 container overlay 的 allowed areas
    ContainerOverlay->setAllowedAreas(AllowedContainerAreas);
    
    // 显示 container overlay 并获取 container 的区域
    DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
    
    // 如果 container 区域有效，则启用 drop preview
    ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
    
    // 如果存在 dock area 并且可见，则显示 dock area overlay
    if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
    {
        DockAreaOverlay->enableDropPreview(true);
        DockAreaOverlay->setAllowedAreas((VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas());
        DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
        
        // 如果 dockAreaOverlay() 的区域是 CenterDockWidgetArea，则表示鼠标在标题栏上
        // 如果 ContainerArea 有效，则忽略 dockAreaOverlay() 的 dock area，并禁用 drop preview
        if ((Area == CenterDockWidgetArea) && (ContainerArea != InvalidDockWidgetArea))
        {
            DockAreaOverlay->enableDropPreview(false);
            ContainerOverlay->enableDropPreview(true);
        }
        else
        {
            ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
        }
    }
    else
    {
        DockAreaOverlay->hideOverlay();
    }
}


//============================================================================
// 处理按下 Escape 键的事件
void FloatingDockContainerPrivate::handleEscapeKey()
{
    ADS_PRINT("FloatingDockContainerPrivate::handleEscapeKey()");
    setState(DraggingInactive);
    DockManager->containerOverlay()->hideOverlay();
    DockManager->dockAreaOverlay()->hideOverlay();
}

//============================================================================
// CFloatingDockContainer 构造函数
// 初始化 CFloatingDockContainer 对象
CFloatingDockContainer::CFloatingDockContainer(CDockManager *DockManager) :
    tFloatingWidgetBase(DockManager),
    d(new FloatingDockContainerPrivate(this))
{
    d->DockManager = DockManager;
    d->DockContainer = new CDockContainerWidget(DockManager, this);
    connect(d->DockContainer, SIGNAL(dockAreasAdded()), this, SLOT(onDockAreasAddedOrRemoved()));
    connect(d->DockContainer, SIGNAL(dockAreasRemoved()), this, SLOT(onDockAreasAddedOrRemoved()));

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    QDockWidget::setWidget(d->DockContainer);
    QDockWidget::setFloating(true);
    QDockWidget::setFeatures(QDockWidget::DockWidgetClosable
        | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);

    bool native_window = true;

    // 如果设置了 "ADS_UseNativeTitle" 环境变量，则覆盖 FloatingContainerForce*TitleBar
    auto env = qgetenv("ADS_UseNativeTitle").toUpper();

    if (env == "1")
    {
        native_window = true;
    }
    else if (env == "0")
    {
        native_window = false;
    }
    else if (DockManager->testConfigFlag(CDockManager::FloatingContainerForceNativeTitleBar))
    {
        native_window = true;
    }
    else if (DockManager->testConfigFlag(CDockManager::FloatingContainerForceQWidgetTitleBar))
    {
        native_window = false;
    }
    else
    {
        // KDE 似乎在移动窗口时不会触发 MoveEvents，所以暂时对所有使用 KWin 的窗口禁用原生标题栏。
        QString window_manager = internal::windowManager().toUpper().split(" ")[0];
        native_window = window_manager != "KWIN";
    }

    if (native_window)
    {
        setTitleBarWidget(new QWidget());
        setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
    }
    else
    {
        d->TitleBar = new CFloatingWidgetTitleBar(this);
        setTitleBarWidget(d->TitleBar);
        setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
        d->TitleBar->enableCloseButton(isClosable());
        connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
        connect(d->TitleBar, &CFloatingWidgetTitleBar::maximizeRequested,
                this, &CFloatingDockContainer::onMaximizeRequest);
    }
#else
    setWindowFlags(
        Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
    QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom);
    l->setContentsMargins(0, 0, 0, 0);
    l->setSpacing(0);
    setLayout(l);
    l->addWidget(d->DockContainer);
#endif

    DockManager->registerFloatingWidget(this);
}

//============================================================================
// CFloatingDockContainer 构造函数
// 初始化 CFloatingDockContainer 对象，并指定 DockArea
CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget *DockArea) :
    CFloatingDockContainer(DockArea->dockManager())
{
    d->DockContainer->addDockArea(DockArea);
    auto TopLevelDockWidget = topLevelDockWidget();

    if (TopLevelDockWidget)
    {
        TopLevelDockWidget->emitTopLevelChanged(true);
    }

    d->DockManager->notifyWidgetOrAreaRelocation(DockArea);
}

//============================================================================
// CFloatingDockContainer 构造函数
// 初始化 CFloatingDockContainer 对象，并指定 DockWidget
CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) :
    CFloatingDockContainer(DockWidget->dockManager())
{
    d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget);
    auto TopLevelDockWidget = topLevelDockWidget();

    if (TopLevelDockWidget)
    {
        TopLevelDockWidget->emitTopLevelChanged(true);
    }

    d->DockManager->notifyWidgetOrAreaRelocation(DockWidget);
}

//============================================================================
// CFloatingDockContainer 的析构函数
CFloatingDockContainer::~CFloatingDockContainer()
{
    ADS_PRINT("~CFloatingDockContainer");
    if (d->DockManager)
    {
        d->DockManager->removeFloatingWidget(this);
    }
    delete d;
}

//============================================================================
// 获取 dock container
CDockContainerWidget* CFloatingDockContainer::dockContainer() const
{
    return d->DockContainer;
}

//============================================================================
// 处理浮动 dock container 的事件
void CFloatingDockContainer::changeEvent(QEvent *event)
{
    Super::changeEvent(event);
    switch (event->type())
    {
    case QEvent::ActivationChange:
        if (isActiveWindow())
        {
            ADS_PRINT("FloatingWidget::changeEvent QEvent::ActivationChange ");
            d->zOrderIndex = ++zOrderCounter;

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
            if (d->DraggingState == DraggingFloatingWidget)
            {
                d->titleMouseReleaseEvent();
                d->DraggingState = DraggingInactive;
            }
#endif
        }
        break;

    case QEvent::WindowStateChange:
        // 如果 DockManager 窗口从最小化状态恢复，则浮动窗口不会正确恢复到最大化状态，而是恢复到正常状态。
        // 我们在这里简单地检查浮动窗口之前是否是最大化状态，如果 DockManager 正在离开最小化状态，则恢复浮动窗口的最大化状态。
        if (d->DockManager->isLeavingMinimizedState())
        {
            QWindowStateChangeEvent* ev = static_cast<QWindowStateChangeEvent*>(event);
            if (ev->oldState().testFlag(Qt::WindowMaximized))
            {
                this->showMaximized();
            }
        }
        break;

    default:
        break; // 什么都不做
    }
}


#ifdef Q_OS_WIN
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *message, long *result)
#else
bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
#endif
{
    QWidget::nativeEvent(eventType, message, result);
    MSG *msg = static_cast<MSG*>(message);
    switch (msg->message)
    {
        case WM_MOVING:
        {
            if (d->isState(DraggingFloatingWidget))
            {
                d->updateDropOverlays(QCursor::pos());
            }
        }
        break;

        case WM_NCLBUTTONDOWN:
            if (msg->wParam == HTCAPTION && d->isState(DraggingInactive))
            {
                ADS_PRINT("CFloatingDockContainer::nativeEvent WM_NCLBUTTONDOWN");
                d->DragStartPos = pos();
                d->setState(DraggingMousePressed);
            }
            break;

        case WM_NCLBUTTONDBLCLK:
            d->setState(DraggingInactive);
            break;

        case WM_ENTERSIZEMOVE:
            if (d->isState(DraggingMousePressed))
            {
                ADS_PRINT("CFloatingDockContainer::nativeEvent WM_ENTERSIZEMOVE");
                d->setState(DraggingFloatingWidget);
                d->updateDropOverlays(QCursor::pos());
            }
            break;

        case WM_EXITSIZEMOVE:
            if (d->isState(DraggingFloatingWidget))
            {
                ADS_PRINT("CFloatingDockContainer::nativeEvent WM_EXITSIZEMOVE");
                if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
                {
                    d->handleEscapeKey();
                }
                else
                {
                    d->titleMouseReleaseEvent();
                }
            }
            break;
    }
    return false;
}
#endif


//============================================================================
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
{
    // 打印日志
    ADS_PRINT("CFloatingDockContainer closeEvent");
    
    // 设置状态为DraggingInactive
    d->setState(DraggingInactive);
    
    // 忽略事件
    event->ignore();

    // 如果不可关闭，直接返回
    if (!isClosable())
    {
        return;
    }

    // 是否有打开的DockWidgets
    bool HasOpenDockWidgets = false;

    // 遍历所有打开的DockWidgets
    for (auto DockWidget : d->DockContainer->openedDockWidgets())
    {
        // 如果DockWidget支持DockWidgetDeleteOnClose或CustomCloseHandling特性
        if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) || DockWidget->features().testFlag(CDockWidget::CustomCloseHandling))
        {
            // 关闭DockWidget
            bool Closed = DockWidget->closeDockWidgetInternal();
            if (!Closed)
            {
                HasOpenDockWidgets = true;
            }
        }
        else
        {
            // 隐藏DockWidget
            DockWidget->toggleView(false);
        }
    }

    // 如果有打开的DockWidgets，直接返回
    if (HasOpenDockWidgets)
    {
        return;
    }

    // 在Qt版本5.9.2之后似乎存在一个bug，导致QWidget::event()函数在关闭/显示循环后不再接收任何非客户区域鼠标事件
    // 这个bug在这里报告：https://bugreports.qt.io/browse/QTBUG-73295
    // 下面的代码是对Qt版本>5.9.2的一个解决方法，似乎有效
    // 从Qt版本5.12.2开始，这个问题似乎又可以正常工作了。但是现在QEvent::NonClientAreaMouseButtonPress函数总是返回Qt::RightButton，即使按下了左键
    this->hide();
}
//============================================================================
void CFloatingDockContainer::hideEvent(QHideEvent *event)
{
    // 调用父类的hideEvent函数
    Super::hideEvent(event);

    // 如果是自发的事件，直接返回
    if (event->spontaneous())
    {
        return;
    }

    // 在恢复状态期间阻止toggleView()事件
    if (d->DockManager->isRestoringState())
    {
        return;
    }

    // 如果AutoHideChildren为true，隐藏所有打开的DockWidgets
    if (d->AutoHideChildren)
    {
        d->Hiding = true;
        for (auto DockArea : d->DockContainer->openedDockAreas())
        {
            for (auto DockWidget : DockArea->openedDockWidgets())
            {
                DockWidget->toggleView(false);
            }
        }
        d->Hiding = false;
    }
}
//============================================================================
void CFloatingDockContainer::showEvent(QShowEvent *event)
{
    // 调用父类的showEvent函数
    Super::showEvent(event);

    // 在Unix系统（非MacOS）上，如果CDockManager::FocusHighlighting配置标志被设置，激活窗口
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
    {
        this->window()->activateWindow();
    }
#endif
}
//============================================================================
void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
    const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
{
    // 在Unix系统（非MacOS）上，如果没有最大化，设置大小和拖动起始鼠标位置
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    if (!isMaximized())
    {
        resize(Size);
        d->DragStartMousePosition = DragStartMousePos;
    }
    d->setState(DragState);
    if (DraggingFloatingWidget == DragState)
    {
        d->MouseEventHandler = MouseEventHandler;
        if (d->MouseEventHandler)
        {
            d->MouseEventHandler->grabMouse();
        }
    }
    if (!isMaximized())
    {
        moveFloating();
    }
    show();
#else
    Q_UNUSED(MouseEventHandler)
    resize(Size);
    d->DragStartMousePosition = DragStartMousePos;
    d->setState(DragState);
    moveFloating();
    show();
#endif
}

//============================================================================
void CFloatingDockContainer::moveFloating()
{
    // 计算边框大小
    int BorderSize = (frameSize().width() - size().width()) / 2;
    // 计算移动位置
    const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
        - QPoint(BorderSize, 0);
    // 移动窗口
    move(moveToPos);
    
    // 根据拖拽状态进行处理
    switch (d->DraggingState)
    {
    case DraggingMousePressed:
        // 设置状态为拖拽浮动窗口
        d->setState(DraggingFloatingWidget);
        // 更新放置覆盖层
        d->updateDropOverlays(QCursor::pos());
        break;
    case DraggingFloatingWidget:
        // 更新放置覆盖层
        d->updateDropOverlays(QCursor::pos());
#ifdef Q_OS_MACOS
        // 在OSX中，隐藏DockAreaOverlay后应用程序会将主窗口设置为活动窗口，这里通过将活动窗口重置为浮动窗口来修复这个问题
        activateWindow();
#endif
        break;
    default:
        break;
    }
}
//============================================================================
bool CFloatingDockContainer::isClosable() const
{
    // 判断是否可关闭
    return d->DockContainer->features().testFlag(
        CDockWidget::DockWidgetClosable);
}
//============================================================================
void CFloatingDockContainer::onDockAreasAddedOrRemoved()
{
    ADS_PRINT("CFloatingDockContainer::onDockAreasAddedOrRemoved()");
    // 获取顶层DockArea
    auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
    if (TopLevelDockArea)
    {
        // 设置单个DockArea
        d->SingleDockArea = TopLevelDockArea;
        CDockWidget* CurrentWidget = d->SingleDockArea->currentDockWidget();
        // 反映当前widget
        d->reflectCurrentWidget(CurrentWidget);
        // 连接currentChanged信号与槽函数
        connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
            SLOT(onDockAreaCurrentChanged(int)));
    }
    else
    {
        if (d->SingleDockArea)
        {
            // 断开currentChanged信号与槽函数的连接
            disconnect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
                SLOT(onDockAreaCurrentChanged(int)));
            d->SingleDockArea = nullptr;
        }
        // 设置窗口标题和图标
        d->setWindowTitle(d->floatingContainersTitle());
        setWindowIcon(QApplication::windowIcon());
    }
}
//============================================================================
void CFloatingDockContainer::updateWindowTitle()
{
    // 如果浮动容器将被隐藏，则不需要更新窗口标题
    if (d->Hiding)
    {
        return;
    }
    // 获取顶层DockArea
    auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
    if (TopLevelDockArea)
    {
        CDockWidget* CurrentWidget = TopLevelDockArea->currentDockWidget();
        if (CurrentWidget)
        {
            // 反映当前widget
            d->reflectCurrentWidget(CurrentWidget);
        }
    }
    else
    {
        // 设置窗口标题和图标
        d->setWindowTitle(d->floatingContainersTitle());
        setWindowIcon(QApplication::windowIcon());
    }
}
//============================================================================
void CFloatingDockContainer::onDockAreaCurrentChanged(int Index)
{
    Q_UNUSED(Index);
    CDockWidget* CurrentWidget = d->SingleDockArea->currentDockWidget();
    // 反映当前widget
    d->reflectCurrentWidget(CurrentWidget);
}
//============================================================================
bool CFloatingDockContainer::restoreState(CDockingStateReader &Stream,
    bool Testing)
{
    if (!d->DockContainer->restoreState(Stream, Testing))
    {
        return false;
    }
    // 处理dock区域添加或删除事件
    onDockAreasAddedOrRemoved();
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    if(d->TitleBar)
    {
        // 设置最大化图标
        d->TitleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
    }
#endif
    return true;
}


// 判断浮动容器中是否有顶级停靠窗口
bool CFloatingDockContainer::hasTopLevelDockWidget() const
{
    return d->DockContainer->hasTopLevelDockWidget();
}

// 获取浮动容器中的顶级停靠窗口
CDockWidget* CFloatingDockContainer::topLevelDockWidget() const
{
    return d->DockContainer->topLevelDockWidget();
}

// 获取浮动容器中的停靠窗口列表
QList<CDockWidget*> CFloatingDockContainer::dockWidgets() const
{
    return d->DockContainer->dockWidgets();
}

// 隐藏并延迟删除浮动容器
void CFloatingDockContainer::hideAndDeleteLater()
{
    // Widget已重新停靠，因此必须立即隐藏（参见
    // https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/351）
    // 但是AutoHideChildren必须设置为false，因为“this”仍然包含不应该切换隐藏的停靠窗口。
    d->AutoHideChildren = false;
    hide();
    deleteLater();
    if (d->DockManager)
    {
        d->DockManager->removeFloatingWidget(this);
        d->DockManager->removeDockContainer(this->dockContainer());
    }
}

// 完成拖动操作
void CFloatingDockContainer::finishDragging()
{
    ADS_PRINT("CFloatingDockContainer::finishDragging");
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    setWindowOpacity(1);
    activateWindow();
    if (d->MouseEventHandler)
    {
        d->MouseEventHandler->releaseMouse();
        d->MouseEventHandler = nullptr;
    }
#endif
    d->titleMouseReleaseEvent();
}

#ifdef Q_OS_MACOS
//============================================================================

// 定义一个函数，该函数用于处理事件
bool CFloatingDockContainer::event(QEvent *e)
{
    // 根据不同的拖动状态进行处理
    switch (d->DraggingState)
    {
    case DraggingInactive:
    {
        // 通常情况下，我们会在这里检查左鼠标按钮是否被按下
        // 但是从QT版本5.12.2开始，来自QEvent::NonClientAreaMouseButtonPress的鼠标事件返回错误的鼠标按钮
        // 该事件总是返回Qt::RightButton，即使左键被点击
        // 为了解决整个非客户区鼠标区域的问题，真是太棒了
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
        if (e->type() == QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
#else
        if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
        {
            ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
            d->DragStartPos = pos();
            d->setState(DraggingMousePressed);
        }
    }
    break;
    case DraggingMousePressed:
        switch (e->type())
        {
        case QEvent::NonClientAreaMouseButtonDblClick:
            ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick");
            d->setState(DraggingInactive);
            break;
        case QEvent::Resize:
            // 如果鼠标按下后的第一个事件是调整大小事件，那么用户是在调整窗口大小而不是拖动它
            // 但有一个例外情况，如果窗口是最大化的，那么通过标题栏拖动窗口会导致小部件离开最大化状态。这将触发调整大小事件
            // 为了知道调整大小事件是由用户通过移动窗口边框的角触发还是由窗口状态改变引起的，我们检查是否不是最大化状态
            if (!isMaximized())
            {
                d->setState(DraggingInactive);
            }
            break;
        default:
            break;
        }
        break;
    case DraggingFloatingWidget:
        if (e->type() == QEvent::NonClientAreaMouseButtonRelease)
        {
            ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease");
            d->titleMouseReleaseEvent();
        }
        break;
    default:
        break;
    }
#if (ADS_DEBUG_LEVEL > 0)
    qDebug() << QTime::currentTime() << "CFloatingDockContainer::event " << e->type();
#endif
    return QWidget::event(e);
}

//============================================================================

// 定义一个函数，该函数用于处理移动事件
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
{
    QWidget::moveEvent(event);
    switch (d->DraggingState)
    {
    case DraggingMousePressed:
        d->setState(DraggingFloatingWidget);
        d->updateDropOverlays(QCursor::pos());
        break;
    case DraggingFloatingWidget:
        d->updateDropOverlays(QCursor::pos());
        // 在OSX中，当隐藏DockAreaOverlay时，应用程序会将主窗口设置为活动窗口，原因不明。通过在更新覆盖层后将活动窗口重置为浮动窗口来修复此问题
        activateWindow();
        break;
    default:
        break;
    }
}
#endif


#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
//============================================================================

// 处理最大化请求的函数
void CFloatingDockContainer::onMaximizeRequest()
{
    if (windowState() == Qt::WindowMaximized)
    {
        showNormal();
    }
    else
    {
        showMaximized();
    }
}

//============================================================================

// 以正常状态显示窗口的函数
void CFloatingDockContainer::showNormal(bool fixGeometry)
{
    if (windowState() == Qt::WindowMaximized)
    {
        QRect oldNormal = normalGeometry();
        Super::showNormal();
        if(fixGeometry)
        {
            setGeometry(oldNormal);
        }
    }
    if(d->TitleBar)
    {
        d->TitleBar->setMaximizedIcon(false);
    }
}

//============================================================================

// 以最大化状态显示窗口的函数
void CFloatingDockContainer::showMaximized()
{
    Super::showMaximized();
    if (d->TitleBar)
    {
        d->TitleBar->setMaximizedIcon(true);
    }
}

//============================================================================

// 检查窗口是否最大化的函数
bool CFloatingDockContainer::isMaximized() const
{
    return windowState() == Qt::WindowMaximized;
}

//============================================================================

// 显示窗口的函数
void CFloatingDockContainer::show()
{
    // 防止窗口在任务栏和分页器（alt+tab）中显示
    internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
    internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
    Super::show();
}

//============================================================================

// 处理调整大小事件的函数
void CFloatingDockContainer::resizeEvent(QResizeEvent *event)
{
    d->IsResizing = true;
    Super::resizeEvent(event);
}

//============================================================================

// 处理移动事件的函数
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
{
    Super::moveEvent(event);
    if (!d->IsResizing && event->spontaneous() && d->MousePressed)
    {
        d->setState(DraggingFloatingWidget);
        d->updateDropOverlays(QCursor::pos());
    }
    d->IsResizing = false;
}

//============================================================================

// 处理其他事件的函数
bool CFloatingDockContainer::event(QEvent *e)
{
    bool result = Super::event(e);
    switch (e->type())
    {
    case QEvent::WindowActivate:
        d->MousePressed = false;
        break;
    case QEvent::WindowDeactivate:
        d->MousePressed = true;
        break;
    default:
        break;
    }
    return result;
}

//============================================================================

// 检查窗口是否有原生标题栏的函数
bool CFloatingDockContainer::hasNativeTitleBar()
{
    return d->TitleBar == nullptr;
}
#endif

} // namespace ads

//---------------------------------------------------------------------------
// EOF FloatingDockContainer.cpp
